﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Predictor_v._1._0
{
    public class MathAdaptiveModel
    {
        private ZedGraph.PointPairList _data;
        private double[,] _arrayData;

        private double _alphaValue;
        private double b_0;
        private double b_1;
        private double t_average;
        private double y_average;
        private double sum_mult_t_by_y;

        private double[] st_1;
        private double[] st_2;
        private double[] b_0_estim;
        private double[] b_1_estim;

        private ZedGraph.PointPairList _model;
        private ZedGraph.PointPairList _prediction;

        public MathAdaptiveModel(ZedGraph.PointPairList data, double alpha)
        {
            this._data = data;
            this._alphaValue = alpha;
            _arrayData = PairListToArray();
            DoCalcBasicModelEstimates();
            CountSt_1();
            CountSt_2();
            CountB_est();
            _model = new ZedGraph.PointPairList();
            CountY_mod();
            _prediction = new ZedGraph.PointPairList();
            CountY_prediction();
        }

        private void DoCalcBasicModelEstimates()
        {
            double sum_t = 0;
            double sum_y = 0;
            double sum_t_na_y = 0;
            double sum_t_square = 0;
            
            for (int i = 0; i < _data.Count; i++)
            {
                sum_t+=_arrayData[0, i];
                sum_y += _arrayData[1, i];
                sum_t_na_y += _arrayData[0, i] * _arrayData[1, i];
                sum_t_square += Math.Pow(_arrayData[0, i],2);
            }

            t_average = sum_t / _data.Count;
            y_average = sum_y / _data.Count;
            sum_mult_t_by_y = sum_t_na_y;
            

            double t1=(sum_mult_t_by_y - (_data.Count * t_average * y_average));
            double t2 = (sum_t_square - _data.Count * Math.Pow(t_average, 2));
            b_1 = t1 / t2;
            b_0 = y_average - b_1 * t_average;
        }

        private double[,] PairListToArray()
        {
            double[,] dataArray = new double[2,_data.Count];
            for (int i = 0; i < _data.Count; i++)
            {
                var i_pair = _data.Where(x => x.X == (i+1));
                dataArray[0, i] = i_pair.Select(x => x.X).First();
                dataArray[1, i] = i_pair.Select(x => x.Y).First();
            }

            return dataArray;
        }

        private void CountSt_1()
        {
            st_1=new double[_data.Count];
            st_1[0] =b_0 - ((1-_alphaValue)/_alphaValue)*b_1;

            for (int i = 1; i < st_1.Length; i++)
            {
                st_1[i] = _alphaValue * _arrayData[1, i] + (1 - _alphaValue) * st_1[i - 1];
            }
        }

        private void CountSt_2()
        {
            st_2 = new double[_data.Count];
            st_2[0] = b_0 - ((2*(1 - _alphaValue)) / _alphaValue) * b_1;

            for (int i = 1; i < st_2.Length; i++)
            {
                st_2[i] = _alphaValue * st_1[i] + (1 - _alphaValue) * st_2[i - 1];
            }
        }

        private void CountB_est()
        {
            b_0_estim = new double[st_1.Length];
            b_1_estim = new double[st_1.Length];

            for (int i = 0; i < st_1.Length; i++)
            {
                b_0_estim[i] = 2 * st_1[i] - st_2[i];
                b_1_estim[i] = (_alphaValue/(1-_alphaValue))*(st_1[i]-st_2[i]);
            }
        }

        private void CountY_mod()
        {
            for (int i = 0; i < b_0_estim.Length; i++)
            {
                _model.Add(i+1, b_0_estim[i]+b_1_estim[i]);
            }
        }

        private void CountY_prediction()
        {
            for (int i = 0; i < 4; i++)
            {
                _prediction.Add(i + 1 + _model.Count, (b_0_estim[_model.Count - 1] + b_1_estim[_model.Count-1] * (i + 2)));
            }
        }

        public ZedGraph.PointPairList GetModel()
        {
            return _model;
        }

        public ZedGraph.PointPairList GetPrediction()
        {
            return _prediction;
        }

        public string GetSt_1()
        {
            return ArrayToString(st_1);
        }

        public string GetSt_2()
        {
            return ArrayToString(st_2);
        }

        public string PairArrayToString()
        {
            string rez = null;

            for (int i = 0; i < (_arrayData.Length / 2); i++)
            {
                rez += string.Format("x{0}: {1}, y{2}: {3}{4}", i, _arrayData[0, i], i, _arrayData[1, i], Environment.NewLine);
            }

            return rez;
        }

        private string ArrayToString(double[] arr)
        {
            string rez = null;

            for (int i = 0; i < arr.Length; i++)
            {
                rez += string.Format("val{0}={1}{2}",i,arr[i], Environment.NewLine);
            }

            return rez;
        }

        public string OnScreenAverages()
        {
            return string.Format("b1 = {0}, b0 = {1}", b_1, b_0);
        }


    }
}
